package com.rules.admin.unit;

import com.gillion.grule.client.core.Context;
import com.gillion.grule.client.core.ContextBuilder;
import com.gillion.grule.client.executor.DroolsRuleExecutor;
import com.gillion.grule.client.logger.LoggerAppenderHolder;
import com.gillion.grule.client.sync.DroolsRulePackage;
import com.gillion.grule.client.utils.Closure;
import com.gillion.grule.client.utils.Streams;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.rules.admin.exceptions.UnitTestException;
import com.rules.admin.unit.expect.Expect;
import com.rules.admin.unit.expect.ExpectMatcherResult;
import com.rules.admin.unit.mock.Mock;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class DroolsUnitCaseExecutor implements UnitCaseExecutor<DroolsRulePackage> {
   private DroolsRuleExecutor droolsRuleExecutor;

   public void execute(DroolsRulePackage rulePackage, UnitCase unitCase) throws NullPointerException {
      this.log("开始执行测试用例：{}", unitCase.getArtifactId());
      this.log("构造入参：{}", unitCase.getInParameters());
      Context context = ContextBuilder.newBuilder().addParams(unitCase.getInParameters()).variable(rulePackage.getVariables()).dataSource(rulePackage.getDataSources()).remoteConfig(rulePackage.getRemoteConfig()).springCloudConfig(rulePackage.getSpringCloudConfig()).dubboConfig(rulePackage.getDubboConfigs()).groovyShellConfig(rulePackage.getGroovyShellConfigs()).validatorConfig(rulePackage.getValidatorConfig()).build();
      this.mockAllComponent(unitCase, context);
      this.droolsRuleExecutor.execute(rulePackage, context);
      if (unitCase.getExpects() == null) {
         throw new NullPointerException("期望为空，请添加！");
      } else {
         Iterable<ExpectMatcherResult> expectResult = this.expectMatch(unitCase, context);
         Streams.of(expectResult).forEach(new Closure<ExpectMatcherResult>() {
            public void execute(ExpectMatcherResult expectMatcherResult) {
               DroolsUnitCaseExecutor.this.log(expectMatcherResult.getMessage());
            }
         });
         Streams.of(expectResult).forEach(new Closure<ExpectMatcherResult>() {
            public void execute(ExpectMatcherResult expectMatcherResult) {
               if (!expectMatcherResult.getMatch()) {
                  throw new UnitTestException("用例测试失败，请检查配置。");
               }
            }
         });
      }
   }

   private void log(String message, Object... args) {
      LoggerAppenderHolder.get().append(message, args);
   }

   private void mockAllComponent(UnitCase unitCase, final Context context) {
      if (unitCase.getMocks() != null) {
         Streams.of(unitCase.getMocks()).forEach(new Closure<Mock>() {
            public void execute(Mock mock) {
               mock.mock(context);
            }
         });
      }

   }

   private List<ExpectMatcherResult> expectMatch(UnitCase unitCase, final Context context) {
      return Streams.of(unitCase.getExpects()).map(new Function<Expect, ExpectMatcherResult>() {
         public ExpectMatcherResult apply(Expect input) {
            return input.expect(context);
         }
      }).filter(new Predicate<ExpectMatcherResult>() {
         public boolean apply(ExpectMatcherResult input) {
            return !input.getMatch();
         }
      }).collectToList();
   }

   public void setRuleExecutor(DroolsRuleExecutor ruleExecutor) {
      this.droolsRuleExecutor = ruleExecutor;
   }
}
